"""
告警处理工作流服务
实现告警的分配、处理、关闭流程，创建告警处理历史的记录和查询，开发告警统计分析和报表功能
"""
import asyncio
import logging
from datetime import datetime, timedelta
from typing import List, Dict, Optional, Any, Callable
from uuid import uuid4
from collections import defaultdict
from enum import Enum
import json

from schemas.alert_management import (
    AlertEvent, AlertStatus, AlertLevel, AlertCategory, AlertQuery,
    AlertStatistics, AlertEventUpdateRequest
)

logger = logging.getLogger(__name__)


class WorkflowAction(str, Enum):
    """工作流动作枚举"""
    ASSIGN = "assign"           # 分配
    ACKNOWLEDGE = "acknowledge"  # 确认
    ESCALATE = "escalate"       # 升级
    RESOLVE = "resolve"         # 解决
    CLOSE = "close"            # 关闭
    REOPEN = "reopen"          # 重新打开
    COMMENT = "comment"        # 添加评论


class WorkflowRule:
    """工作流规则"""
    def __init__(self, rule_id: str, name: str, conditions: Dict[str, Any],
                 actions: List[Dict[str, Any]], enabled: bool = True):
        self.rule_id = rule_id
        self.name = name
        self.conditions = conditions
        self.actions = actions
        self.enabled = enabled


class AlertWorkflowHistory:
    """告警工作流历史记录"""
    def __init__(self, history_id: str, alert_id: str, action: WorkflowAction,
                 user_id: str, timestamp: datetime, details: Dict[str, Any],
                 previous_status: AlertStatus, new_status: AlertStatus):
        self.history_id = history_id
        self.alert_id = alert_id
        self.action = action
        self.user_id = user_id
        self.timestamp = timestamp
        self.details = details
        self.previous_status = previous_status
        self.new_status = new_status


class AlertAssignmentRule:
    """告警分配规则"""
    def __init__(self, rule_id: str, name: str, conditions: Dict[str, Any],
                 assignees: List[str], priority: int = 0):
        self.rule_id = rule_id
        self.name = name
        self.conditions = conditions
        self.assignees = assignees
        self.priority = priority


class AlertEscalationRule:
    """告警升级规则"""
    def __init__(self, rule_id: str, name: str, conditions: Dict[str, Any],
                 escalation_time: int, escalation_targets: List[str]):
        self.rule_id = rule_id
        self.name = name
        self.conditions = conditions
        self.escalation_time = escalation_time  # 升级时间(分钟)
        self.escalation_targets = escalation_targets


class AlertMetricsCalculator:
    """告警指标计算器"""
    
    @staticmethod
    def calculate_resolution_time(alert: AlertEvent) -> Optional[float]:
        """计算解决时间(分钟)"""
        if alert.resolved_at and alert.created_at:
            delta = alert.resolved_at - alert.created_at
            return delta.total_seconds() / 60
        return None
    
    @staticmethod
    def calculate_response_time(alert: AlertEvent) -> Optional[float]:
        """计算响应时间(分钟)"""
        if alert.acknowledged_at and alert.created_at:
            delta = alert.acknowledged_at - alert.created_at
            return delta.total_seconds() / 60
        return None
    
    @staticmethod
    def calculate_mttr(alerts: List[AlertEvent]) -> float:
        """计算平均解决时间(MTTR)"""
        resolution_times = []
        for alert in alerts:
            resolution_time = AlertMetricsCalculator.calculate_resolution_time(alert)
            if resolution_time is not None:
                resolution_times.append(resolution_time)
        
        return sum(resolution_times) / len(resolution_times) if resolution_times else 0.0
    
    @staticmethod
    def calculate_mtta(alerts: List[AlertEvent]) -> float:
        """计算平均确认时间(MTTA)"""
        response_times = []
        for alert in alerts:
            response_time = AlertMetricsCalculator.calculate_response_time(alert)
            if response_time is not None:
                response_times.append(response_time)
        
        return sum(response_times) / len(response_times) if response_times else 0.0


class AlertWorkflowService:
    """告警工作流服务"""
    
    def __init__(self):
        self.alerts: Dict[str, AlertEvent] = {}
        self.workflow_history: List[AlertWorkflowHistory] = []
        self.assignment_rules: List[AlertAssignmentRule] = []
        self.escalation_rules: List[AlertEscalationRule] = []
        self.workflow_rules: List[WorkflowRule] = []
        
        # 用户和角色管理
        self.users: Dict[str, Dict[str, Any]] = {}
        self.user_workload: Dict[str, int] = defaultdict(int)
        
        # 统计信息
        self.stats = {
            'total_alerts': 0,
            'alerts_by_status': defaultdict(int),
            'alerts_by_level': defaultdict(int),
            'alerts_by_category': defaultdict(int),
            'alerts_by_assignee': defaultdict(int),
            'workflow_actions': defaultdict(int)
        }
        
        # 自动化任务
        self.auto_assignment_enabled = True
        self.auto_escalation_enabled = True
        self.escalation_check_interval = 300  # 5分钟检查一次升级
    
    async def add_alert(self, alert_event: AlertEvent) -> AlertEvent:
        """添加告警到工作流"""
        self.alerts[alert_event.alert_id] = alert_event
        self.stats['total_alerts'] += 1
        self.stats['alerts_by_status'][alert_event.status.value] += 1
        self.stats['alerts_by_level'][alert_event.level.value] += 1
        self.stats['alerts_by_category'][alert_event.category.value] += 1
        
        # 自动分配
        if self.auto_assignment_enabled and not alert_event.assigned_to:
            await self._auto_assign_alert(alert_event)
        
        # 记录历史
        await self._add_workflow_history(
            alert_event.alert_id, WorkflowAction.ASSIGN, "system",
            {"action": "alert_created", "auto_assigned": bool(alert_event.assigned_to)},
            AlertStatus.ACTIVE, alert_event.status
        )
        
        logger.info(f"告警已添加到工作流: {alert_event.alert_id}")
        return alert_event
    
    async def assign_alert(self, alert_id: str, assignee: str, user_id: str) -> bool:
        """分配告警"""
        if alert_id not in self.alerts:
            return False
        
        alert = self.alerts[alert_id]
        previous_assignee = alert.assigned_to
        previous_status = alert.status
        
        alert.assigned_to = assignee
        if alert.status == AlertStatus.ACTIVE:
            alert.status = AlertStatus.ACKNOWLEDGED
            alert.acknowledged_at = datetime.now()
        
        # 更新统计
        if previous_assignee:
            self.user_workload[previous_assignee] -= 1
        self.user_workload[assignee] += 1
        self.stats['alerts_by_assignee'][assignee] += 1
        self.stats['workflow_actions']['assign'] += 1
        
        # 记录历史
        await self._add_workflow_history(
            alert_id, WorkflowAction.ASSIGN, user_id,
            {"previous_assignee": previous_assignee, "new_assignee": assignee},
            previous_status, alert.status
        )
        
        logger.info(f"告警已分配: {alert_id} -> {assignee}")
        return True
    
    async def acknowledge_alert(self, alert_id: str, user_id: str, note: Optional[str] = None) -> bool:
        """确认告警"""
        if alert_id not in self.alerts:
            return False
        
        alert = self.alerts[alert_id]
        if alert.status != AlertStatus.ACTIVE:
            return False
        
        previous_status = alert.status
        alert.status = AlertStatus.ACKNOWLEDGED
        alert.acknowledged_at = datetime.now()
        
        # 更新统计
        self.stats['alerts_by_status'][previous_status.value] -= 1
        self.stats['alerts_by_status'][alert.status.value] += 1
        self.stats['workflow_actions']['acknowledge'] += 1
        
        # 记录历史
        await self._add_workflow_history(
            alert_id, WorkflowAction.ACKNOWLEDGE, user_id,
            {"note": note} if note else {},
            previous_status, alert.status
        )
        
        logger.info(f"告警已确认: {alert_id}")
        return True
    
    async def resolve_alert(self, alert_id: str, user_id: str, resolution_note: str) -> bool:
        """解决告警"""
        if alert_id not in self.alerts:
            return False
        
        alert = self.alerts[alert_id]
        if alert.status in [AlertStatus.RESOLVED, AlertStatus.CLOSED]:
            return False
        
        previous_status = alert.status
        alert.status = AlertStatus.RESOLVED
        alert.resolved_at = datetime.now()
        
        # 更新统计
        self.stats['alerts_by_status'][previous_status.value] -= 1
        self.stats['alerts_by_status'][alert.status.value] += 1
        self.stats['workflow_actions']['resolve'] += 1
        
        # 更新用户工作负载
        if alert.assigned_to:
            self.user_workload[alert.assigned_to] -= 1
        
        # 记录历史
        await self._add_workflow_history(
            alert_id, WorkflowAction.RESOLVE, user_id,
            {"resolution_note": resolution_note},
            previous_status, alert.status
        )
        
        logger.info(f"告警已解决: {alert_id}")
        return True
    
    async def close_alert(self, alert_id: str, user_id: str, close_note: Optional[str] = None) -> bool:
        """关闭告警"""
        if alert_id not in self.alerts:
            return False
        
        alert = self.alerts[alert_id]
        if alert.status == AlertStatus.CLOSED:
            return False
        
        previous_status = alert.status
        alert.status = AlertStatus.CLOSED
        alert.closed_at = datetime.now()
        
        # 更新统计
        self.stats['alerts_by_status'][previous_status.value] -= 1
        self.stats['alerts_by_status'][alert.status.value] += 1
        self.stats['workflow_actions']['close'] += 1
        
        # 更新用户工作负载
        if alert.assigned_to and previous_status != AlertStatus.RESOLVED:
            self.user_workload[alert.assigned_to] -= 1
        
        # 记录历史
        await self._add_workflow_history(
            alert_id, WorkflowAction.CLOSE, user_id,
            {"close_note": close_note} if close_note else {},
            previous_status, alert.status
        )
        
        logger.info(f"告警已关闭: {alert_id}")
        return True
    
    async def escalate_alert(self, alert_id: str, escalation_target: str, user_id: str,
                           escalation_reason: str) -> bool:
        """升级告警"""
        if alert_id not in self.alerts:
            return False
        
        alert = self.alerts[alert_id]
        previous_assignee = alert.assigned_to
        previous_status = alert.status
        
        # 重新分配给升级目标
        alert.assigned_to = escalation_target
        
        # 可能需要提升告警级别
        if alert.level == AlertLevel.LOW:
            alert.level = AlertLevel.MEDIUM
        elif alert.level == AlertLevel.MEDIUM:
            alert.level = AlertLevel.HIGH
        elif alert.level == AlertLevel.HIGH:
            alert.level = AlertLevel.CRITICAL
        
        # 更新统计
        if previous_assignee:
            self.user_workload[previous_assignee] -= 1
        self.user_workload[escalation_target] += 1
        self.stats['workflow_actions']['escalate'] += 1
        
        # 记录历史
        await self._add_workflow_history(
            alert_id, WorkflowAction.ESCALATE, user_id,
            {
                "previous_assignee": previous_assignee,
                "escalation_target": escalation_target,
                "escalation_reason": escalation_reason,
                "new_level": alert.level.value
            },
            previous_status, alert.status
        )
        
        logger.info(f"告警已升级: {alert_id} -> {escalation_target}")
        return True
    
    async def reopen_alert(self, alert_id: str, user_id: str, reopen_reason: str) -> bool:
        """重新打开告警"""
        if alert_id not in self.alerts:
            return False
        
        alert = self.alerts[alert_id]
        if alert.status not in [AlertStatus.RESOLVED, AlertStatus.CLOSED]:
            return False
        
        previous_status = alert.status
        alert.status = AlertStatus.ACTIVE
        alert.resolved_at = None
        alert.closed_at = None
        
        # 更新统计
        self.stats['alerts_by_status'][previous_status.value] -= 1
        self.stats['alerts_by_status'][alert.status.value] += 1
        self.stats['workflow_actions']['reopen'] += 1
        
        # 更新用户工作负载
        if alert.assigned_to:
            self.user_workload[alert.assigned_to] += 1
        
        # 记录历史
        await self._add_workflow_history(
            alert_id, WorkflowAction.REOPEN, user_id,
            {"reopen_reason": reopen_reason},
            previous_status, alert.status
        )
        
        logger.info(f"告警已重新打开: {alert_id}")
        return True
    
    async def add_comment(self, alert_id: str, user_id: str, comment: str) -> bool:
        """添加评论"""
        if alert_id not in self.alerts:
            return False
        
        alert = self.alerts[alert_id]
        
        # 记录历史
        await self._add_workflow_history(
            alert_id, WorkflowAction.COMMENT, user_id,
            {"comment": comment},
            alert.status, alert.status
        )
        
        self.stats['workflow_actions']['comment'] += 1
        logger.info(f"告警评论已添加: {alert_id}")
        return True
    
    async def query_alerts(self, query: AlertQuery) -> List[AlertEvent]:
        """查询告警"""
        results = list(self.alerts.values())
        
        # 应用过滤条件
        if query.alert_ids:
            results = [a for a in results if a.alert_id in query.alert_ids]
        
        if query.rule_ids:
            results = [a for a in results if a.rule_id in query.rule_ids]
        
        if query.categories:
            results = [a for a in results if a.category in query.categories]
        
        if query.levels:
            results = [a for a in results if a.level in query.levels]
        
        if query.statuses:
            results = [a for a in results if a.status in query.statuses]
        
        if query.location:
            results = [a for a in results if a.location and query.location in a.location]
        
        if query.camera_id:
            results = [a for a in results if a.camera_id == query.camera_id]
        
        if query.classroom_id:
            results = [a for a in results if a.classroom_id == query.classroom_id]
        
        if query.teacher_id:
            results = [a for a in results if a.teacher_id == query.teacher_id]
        
        if query.assigned_to:
            results = [a for a in results if a.assigned_to == query.assigned_to]
        
        if query.tags:
            results = [a for a in results if any(tag in a.tags for tag in query.tags)]
        
        if query.start_time:
            results = [a for a in results if a.created_at >= query.start_time]
        
        if query.end_time:
            results = [a for a in results if a.created_at <= query.end_time]
        
        # 排序和分页
        results.sort(key=lambda x: x.created_at, reverse=True)
        
        start_idx = query.offset
        end_idx = start_idx + query.limit
        
        return results[start_idx:end_idx]
    
    async def get_alert_statistics(self, start_time: Optional[datetime] = None,
                                 end_time: Optional[datetime] = None) -> AlertStatistics:
        """获取告警统计"""
        alerts = list(self.alerts.values())
        
        # 时间过滤
        if start_time:
            alerts = [a for a in alerts if a.created_at >= start_time]
        if end_time:
            alerts = [a for a in alerts if a.created_at <= end_time]
        
        # 基础统计
        total_alerts = len(alerts)
        active_alerts = len([a for a in alerts if a.status == AlertStatus.ACTIVE])
        resolved_alerts = len([a for a in alerts if a.status == AlertStatus.RESOLVED])
        
        # 按级别统计
        alerts_by_level = defaultdict(int)
        for alert in alerts:
            alerts_by_level[alert.level.value] += 1
        
        # 按类别统计
        alerts_by_category = defaultdict(int)
        for alert in alerts:
            alerts_by_category[alert.category.value] += 1
        
        # 按小时统计
        alerts_by_hour = defaultdict(int)
        for alert in alerts:
            hour_key = alert.created_at.strftime("%Y-%m-%d %H:00")
            alerts_by_hour[hour_key] += 1
        
        # 计算平均解决时间
        avg_resolution_time = AlertMetricsCalculator.calculate_mttr(alerts)
        
        # 主要告警源
        source_counts = defaultdict(int)
        for alert in alerts:
            source = alert.location or alert.camera_id or alert.classroom_id or "未知"
            source_counts[source] += 1
        
        top_alert_sources = [
            {"source": source, "count": count}
            for source, count in sorted(source_counts.items(), key=lambda x: x[1], reverse=True)[:10]
        ]
        
        return AlertStatistics(
            total_alerts=total_alerts,
            active_alerts=active_alerts,
            resolved_alerts=resolved_alerts,
            alerts_by_level=dict(alerts_by_level),
            alerts_by_category=dict(alerts_by_category),
            alerts_by_hour=dict(alerts_by_hour),
            avg_resolution_time=avg_resolution_time,
            top_alert_sources=top_alert_sources
        )
    
    async def get_workflow_history(self, alert_id: Optional[str] = None,
                                 user_id: Optional[str] = None,
                                 action: Optional[WorkflowAction] = None,
                                 limit: int = 100) -> List[AlertWorkflowHistory]:
        """获取工作流历史"""
        history = self.workflow_history
        
        if alert_id:
            history = [h for h in history if h.alert_id == alert_id]
        
        if user_id:
            history = [h for h in history if h.user_id == user_id]
        
        if action:
            history = [h for h in history if h.action == action]
        
        # 按时间倒序排列
        history.sort(key=lambda x: x.timestamp, reverse=True)
        
        return history[:limit]
    
    async def add_assignment_rule(self, rule: AlertAssignmentRule):
        """添加分配规则"""
        self.assignment_rules.append(rule)
        # 按优先级排序
        self.assignment_rules.sort(key=lambda x: x.priority, reverse=True)
        logger.info(f"添加分配规则: {rule.name}")
    
    async def add_escalation_rule(self, rule: AlertEscalationRule):
        """添加升级规则"""
        self.escalation_rules.append(rule)
        logger.info(f"添加升级规则: {rule.name}")
    
    async def _auto_assign_alert(self, alert: AlertEvent):
        """自动分配告警"""
        for rule in self.assignment_rules:
            if self._match_assignment_conditions(alert, rule.conditions):
                # 选择工作负载最少的分配者
                assignee = min(rule.assignees, key=lambda x: self.user_workload.get(x, 0))
                alert.assigned_to = assignee
                self.user_workload[assignee] += 1
                self.stats['alerts_by_assignee'][assignee] += 1
                logger.info(f"自动分配告警: {alert.alert_id} -> {assignee}")
                break
    
    def _match_assignment_conditions(self, alert: AlertEvent, conditions: Dict[str, Any]) -> bool:
        """匹配分配条件"""
        for key, value in conditions.items():
            if key == "category" and alert.category.value != value:
                return False
            elif key == "level" and alert.level.value != value:
                return False
            elif key == "location" and alert.location != value:
                return False
            elif key == "camera_id" and alert.camera_id != value:
                return False
            elif key == "classroom_id" and alert.classroom_id != value:
                return False
        return True
    
    async def _add_workflow_history(self, alert_id: str, action: WorkflowAction,
                                  user_id: str, details: Dict[str, Any],
                                  previous_status: AlertStatus, new_status: AlertStatus):
        """添加工作流历史记录"""
        history = AlertWorkflowHistory(
            history_id=str(uuid4()),
            alert_id=alert_id,
            action=action,
            user_id=user_id,
            timestamp=datetime.now(),
            details=details,
            previous_status=previous_status,
            new_status=new_status
        )
        
        self.workflow_history.append(history)
        
        # 限制历史记录大小
        if len(self.workflow_history) > 10000:
            self.workflow_history = self.workflow_history[-5000:]
    
    async def start_escalation_monitor(self):
        """启动升级监控"""
        while True:
            try:
                await self._check_escalations()
                await asyncio.sleep(self.escalation_check_interval)
            except Exception as e:
                logger.error(f"升级监控错误: {e}")
                await asyncio.sleep(60)
    
    async def _check_escalations(self):
        """检查需要升级的告警"""
        if not self.auto_escalation_enabled:
            return
        
        now = datetime.now()
        
        for alert in self.alerts.values():
            if alert.status not in [AlertStatus.ACTIVE, AlertStatus.ACKNOWLEDGED]:
                continue
            
            for rule in self.escalation_rules:
                if self._match_assignment_conditions(alert, rule.conditions):
                    # 检查是否超过升级时间
                    time_since_created = (now - alert.created_at).total_seconds() / 60
                    
                    if time_since_created >= rule.escalation_time:
                        # 选择升级目标
                        escalation_target = min(rule.escalation_targets,
                                              key=lambda x: self.user_workload.get(x, 0))
                        
                        await self.escalate_alert(
                            alert.alert_id, escalation_target, "system",
                            f"自动升级: 超过{rule.escalation_time}分钟未处理"
                        )
                        break
    
    def get_service_stats(self) -> Dict[str, Any]:
        """获取服务统计"""
        return {
            **self.stats,
            'assignment_rules': len(self.assignment_rules),
            'escalation_rules': len(self.escalation_rules),
            'workflow_history_size': len(self.workflow_history),
            'user_workload': dict(self.user_workload),
            'auto_assignment_enabled': self.auto_assignment_enabled,
            'auto_escalation_enabled': self.auto_escalation_enabled
        }